/*
 * Galaxium Messenger
 * Copyright (C) 2003-2007 Philippe Durand <draekz@gmail.com>
 * Copyright (C) 2007 Ben Motmans <ben.motmans@gmail.com>
 * 
 * License: GNU General Public License (GPL)
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 2 of the License, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

using System;
using System.IO;
using System.Collections.Generic;

using Galaxium.Core;

namespace Galaxium.Protocol
{
	public abstract class AbstractSession : ISession
	{
		public event EventHandler<SessionEventArgs> Connected;
		public event EventHandler<SessionEventArgs> Disconnected;
		public event EventHandler<SessionEventArgs> LoginCompleted;
		public event EventHandler<SessionProgressEventArgs> LoginProgress;
		
		public event EventHandler<ContactListEventArgs> ContactAdded;
		public event EventHandler<ContactListEventArgs> ContactRemoved;
		public event EventHandler<ContactEventArgs> ContactChanged;
		public event EventHandler<ContactEventArgs> ContactReverse;
		public event EntityChangeEventHandler<string> ContactDisplayNameChanged;
		public event EntityChangeEventHandler<IPresence> ContactPresenceChanged;
		public event EntityChangeEventHandler<string> ContactDisplayMessageChanged;
		public event EntityChangeEventHandler<IDisplayImage> ContactDisplayImageChanged;
		public event EventHandler<ConversationEventArgs> ConversationRequested;
		public event EventHandler<ConversationEventArgs> ConversationInitiated;
		
		public event EventHandler<FileTransferEventArgs> TransferInvitationReceived;
		public event EventHandler<FileTransferEventArgs> TransferInvitationSent;
		
		public event EventHandler<GroupEventArgs> GroupAdded;
		public event EventHandler<GroupEventArgs> GroupRemoved;
		public event EventHandler<GroupEventArgs> GroupRenamed;
		
		public event EventHandler<ErrorEventArgs> ErrorOccurred;
		
		protected IAccount _account;
		protected IConversationManager _conversations;
		
		protected List<IFileTransfer> _listFileTransfers;
		protected List<IFileTransfer> _activeFileTransfers;
		
		public IList<IFileTransfer> AllFileTransfers
		{
			get { return _listFileTransfers; }
		}
		
		public IList<IFileTransfer> ActiveFileTransfers
		{
			get { return _activeFileTransfers; }
		}
		
		protected AbstractSession (IAccount account)
		{
			ThrowUtility.ThrowIfNull ("account", account);
			
			_account = account;
			_account.Session = this;
			
			_listFileTransfers = new List<IFileTransfer> ();
			_activeFileTransfers = new List<IFileTransfer> ();
		}
		
		public IAccount Account
		{
			get { return _account; }
		}
		
		public IConversationManager Conversations
		{
			get { return _conversations; }
			set { _conversations = value; }
		}
		
		public abstract ContactCollection ContactCollection { get; }
		
		public virtual GroupCollection GroupCollection
		{
			get { return null; }
		}
		
		public abstract void Connect ();
		
		public abstract void Disconnect ();
		
		public void Dispose ()
		{
			Dispose (true);
			GC.SuppressFinalize (this);
		}
		
		protected virtual void Dispose (bool disposing)
		{
		}
		
		public virtual IFileTransfer SendFile (IContact contact, string fileName)
		{
			throw new NotSupportedException ();
		}
		
		protected virtual void OnConnected (SessionEventArgs args)
		{
			if (Connected != null)
				Connected (this, args);
		}
		
		protected virtual void OnDisconnected (SessionEventArgs args)
		{
			if (Disconnected != null)
				Disconnected (this, args);
		}
		
		protected virtual void OnLoginProgress (SessionProgressEventArgs args)
		{
			if (LoginProgress != null)
				LoginProgress (this, args);
		}
		
		protected virtual void OnLoginCompleted (SessionEventArgs args)
		{
			if (LoginCompleted != null)
				LoginCompleted (this, args);
		}
		
		protected virtual void OnConversationInitiated (ConversationEventArgs args)
		{
			if (ConversationInitiated != null)
				ConversationInitiated (this, args);
		}
		
		protected virtual void OnConversationRequested (ConversationEventArgs args)
		{
			if (ConversationRequested != null)
				ConversationRequested (this, args);
		}
		
		protected virtual void OnContactAdded (ContactListEventArgs args)
		{
			if (ContactAdded != null)
				ContactAdded (this, args);
		}
		
		protected virtual void OnContactRemoved (ContactListEventArgs args)
		{
			if (ContactRemoved != null)
				ContactRemoved (this, args);
		}
		
		protected virtual void OnContactReverse (ContactEventArgs args)
		{
			if (ContactReverse != null)
				ContactReverse (this, args);
		}
		
		protected virtual void OnContactChanged (ContactEventArgs args)
		{
			if (ContactChanged != null)
				ContactChanged (this, args);
		}
		
		protected virtual void OnContactNameChanged (EntityChangeEventArgs<string> args)
		{
			if (ContactDisplayNameChanged != null)
				ContactDisplayNameChanged(this, args);
		}
		
		protected virtual void OnContactDisplayMessageChanged (EntityChangeEventArgs<string> args)
		{
			if (ContactDisplayMessageChanged != null)
				ContactDisplayMessageChanged(this, args);
		}
		
		protected virtual void OnContactPresenceChanged (EntityChangeEventArgs<IPresence> args)
		{
			if (ContactPresenceChanged != null)
				ContactPresenceChanged (this, args);
		}
		
		protected virtual void OnContactDisplayImageChanged (EntityChangeEventArgs<IDisplayImage> args)
		{
			if (ContactDisplayImageChanged != null)
				ContactDisplayImageChanged (this, args);
		}
		
		protected virtual void OnTransferInvitationReceived (FileTransferEventArgs args)
		{
			AllFileTransfers.Add (args.FileTransfer);
			
			args.FileTransfer.TransferCancel += TransferCancelled;
			args.FileTransfer.TransferDecline += TransferDeclined;
			
			if (TransferInvitationReceived != null)
				TransferInvitationReceived (this, args);
		}
		
		protected virtual void OnTransferInvitationSent (FileTransferEventArgs args)
		{
			AllFileTransfers.Add (args.FileTransfer);
			
			args.FileTransfer.TransferCancel += TransferCancelled;
			args.FileTransfer.TransferDecline += TransferDeclined;
			
			if (TransferInvitationSent != null)
				TransferInvitationSent (this, args);
		}
		
		private void TransferDeclined (object sender, FileTransferEventArgs args)
		{
			AllFileTransfers.Remove (args.FileTransfer);
			
			args.FileTransfer.TransferDecline -= TransferDeclined;
			args.FileTransfer.TransferCancel -= TransferCancelled;
		}
		
		private void TransferCancelled (object sender, FileTransferEventArgs args)
		{
			AllFileTransfers.Remove (args.FileTransfer);
			
			args.FileTransfer.TransferCancel -= TransferCancelled;
			args.FileTransfer.TransferDecline -= TransferDeclined;
		}
		
		protected virtual void OnGroupAdded (GroupEventArgs args)
		{
			if (GroupAdded != null)
				GroupAdded (this, args);
		}
		
		protected virtual void OnGroupRemoved (GroupEventArgs args)
		{
			if (GroupRemoved != null)
				GroupRemoved (this, args);
		}
		
		protected virtual void OnGroupRenamed (GroupEventArgs args)
		{
			if (GroupRenamed != null)
				GroupRenamed (this, args);
		}
		
		protected virtual void OnErrorOccurred (ErrorEventArgs args)
		{
			if (ErrorOccurred != null)
				ErrorOccurred (this, args);
		}
		
		public void EmitErrorOccurred (ErrorEventArgs args)
		{
			OnErrorOccurred (args);
		}
		
		public void EmitContactChanged (ContactEventArgs args)
		{
			OnContactChanged (args);
		}
		
		public void EmitContactPresenceChanged (EntityChangeEventArgs<IPresence> args)
		{
			OnContactPresenceChanged (args);
		}
		
		public void EmitContactNameChanged (EntityChangeEventArgs<string> args)
		{
			OnContactNameChanged (args);
		}
		
		public void EmitContactDisplayImageChanged (EntityChangeEventArgs<IDisplayImage> args)
		{
			OnContactDisplayImageChanged (args);
		}
		
		public void EmitContactDisplayMessageChanged (EntityChangeEventArgs<string> args)
		{
			OnContactDisplayMessageChanged (args);
		}
		
		public void EmitConversationInitiated (ConversationEventArgs args)
		{
			OnConversationInitiated (args);
		}
		
		public void EmitContactReverse (ContactEventArgs args)
		{
			OnContactReverse (args);
		}
		
		public void EmitLoginProgress (SessionProgressEventArgs args)
		{
			OnLoginProgress (args);
		}
		
		public void EmitLoginCompleted (SessionEventArgs args)
		{
			OnLoginCompleted (args);
		}
		
		public void EmitContactAdded (ContactListEventArgs args)
		{
			OnContactAdded (args);
		}
		
		public void EmitContactRemoved (ContactListEventArgs args)
		{
			OnContactRemoved (args);
		}
		
		public void EmitGroupAdded (GroupEventArgs args)
		{
			OnGroupAdded (args);
		}
		
		public void EmitGroupRemoved (GroupEventArgs args)
		{
			OnGroupRemoved (args);
		}
		
		public void EmitGroupRenamed (GroupEventArgs args)
		{
			OnGroupRenamed (args);
		}
		
		public void EmitTransferInvitationReceived (FileTransferEventArgs args)
		{
			OnTransferInvitationReceived (args);
		}
		
		public void EmitTransferInvitationSent (FileTransferEventArgs args)
		{
			OnTransferInvitationSent (args);
		}
		
		public virtual IEntity FindEntity (string uid)
		{
			if (uid == Account.UniqueIdentifier)
				return Account;
			
			lock (ContactCollection)
				return ContactCollection.GetContact (uid);
		}
		
		public abstract void SetPresence (BasePresence presence);
		
		public virtual bool InContactList (IContact contact)
		{
			return (contact.Session == this);
		}
	}
}